<?php if (!defined('BASEPATH'))exit('No direct script access allowed');

include_once 'ExceptionDAO.php';
include_once 'util/MapError.php';
include_once 'TOEmprestimo.php';
include_once 'TOEmprestimoItem.php';
include_once 'TOItem.php';
include_once 'TOTipo.php';

/**
 * DAO para operações de banco para empréstimo
 * 
 * @author Douglas Rafael
 */
class DAOEmprestimo extends CI_Model {
    var $erro_number;

    /**
     * retorna todos os emprestimo cadastrados
     * 
     * @param type $init
     * @param type $quant
     * @param type $orderby
     * @param type $direction
     * @return array
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function select_all_loans($init, $quant, $orderby = NULL, $direction = NULL) {
        try {
            $orderby != NULL && $direction != NULL ? $this->db->order_by($orderby, $direction) : $this->db->order_by('e.data_saida', 'DESC');
            $this->db->select('e.id, e.data_saida, e.data_retorno, e.usuario_id, e.usuario_admin_id, e_item.status');
            $this->db->join('emprestimo_has_item e_item', 'e_item.emprestimo_id = e.id');
            $this->db->group_by('e_item.emprestimo_id');
            $result = $this->db->get('emprestimo e', $quant, $init);
            
            //Caso ocorra erro no select
            if (!$result) {
                throw new Exception('Ocorreu um erro de banco de dados ao tentar selecionar empréstimo.');
            } else {
                //Carregando models necessários
                $this->load->model('DAOUsuario');
                $emprestimos = array();
                foreach ($result->result() as $value) {
                    $emprestimo = new TOEmprestimo();
                    $emprestimo->id = $value->id;
                    $emprestimo->data_saida = $value->data_saida;
                    $emprestimo->data_retorno = $value->data_retorno;
                    $emprestimo->emprestimo_item = new TOEmprestimoItem();
                    $emprestimo->emprestimo_item = $this->get_loans($emprestimo->id);
                    
                    //Usuário que solicitou o empréstimo e admin que realizou o empréstimo
                    $emprestimo->usuario = $this->DAOUsuario->get_user($value->usuario_id);
                    $emprestimo->usuario_admin = $this->DAOUsuario->get_user($value->usuario_admin_id);
                    
                    array_push($emprestimos, $emprestimo);
                }
                return $emprestimos;
            }
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    /**
     * Retorna os empréstimo sque estão ATIVOS com data de entrrega VENCIDAS ou Com data de entraga par ao dia atual
     * 
     * @return array            Array de objeto
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function select_all_loans_loser($current_date = FALSE) {
        try {
            $operador = $current_date === TRUE ? '=' : '<'; 
            $result = $this->db->query("
                            SELECT 
                              e.id,
                              e.data_saida,
                              e.data_retorno,
                              e.usuario_id,
                              e.usuario_admin_id,
                              e_item.status 
                            FROM (emprestimo e) 
                              JOIN emprestimo_has_item e_item 
                                ON e_item.emprestimo_id = e.id 
                            WHERE data_retorno $operador current_date() 
                            GROUP BY e_item.emprestimo_id
                            ORDER BY DATEDIFF(NOW(), e.data_retorno) DESC 
                       ");
            
            //Caso ocorra erro no select
            if (!$result) {
                throw new Exception('Ocorreu um erro de banco de dados ao tentar selecionar empréstimo.');
            } else {
                //Carregando models necessários
                $this->load->model('DAOUsuario');
                $emprestimos = array();
                $emp_item = new TOEmprestimoItem();
                foreach ($result->result() as $value) {
                    $emprestimo = new TOEmprestimo();
                    $emprestimo->id = $value->id;
                    $emprestimo->data_saida = $value->data_saida;
                    $emprestimo->data_retorno = $value->data_retorno;
                    $emprestimo->emprestimo_item = new TOEmprestimoItem();
                    $emprestimo->emprestimo_item = $this->get_loans($emprestimo->id);
                    
                    //Usuário que solicitou o empréstimo e admin que realizou o empréstimo
                    $emprestimo->usuario = $this->DAOUsuario->get_user($value->usuario_id);
                    $emprestimo->usuario_admin = $this->DAOUsuario->get_user($value->usuario_admin_id);
                    
                    $status = array();
                    foreach ($emprestimo->emprestimo_item as $emprestimo_item) {
                        array_push($status, $emprestimo_item->status);
                    }
                    $status_name = $emp_item->get_status_loan($status, NULL, TRUE);
                    
                    /** Adiciona no array apenas os emprestimos ATIVOS com data de entrega vencida **/
                    if ($status_name === TRUE) {
                        array_push($emprestimos, $emprestimo);
                    }
                }
                return $emprestimos;
            }
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    
   /**
     * Retorna o empréstimo de acordo com o id
     * - Um emprestimo pode ter vários emprestimos (subemprestimos) de itens
     * 
     * @param  TOEmprestimo $emprestimo     Objeto contendo o id do emprestimo
     * @return TOEmprestimo $emprestimo     obejto contendo os dados
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function get_loan(TOEmprestimo $emprestimo) {
        try {
            $this->db->where('id', $emprestimo->id);
            $result = $this->db->get('emprestimo', 1);

            if (!$result) {
                throw new Exception('Ocorreu um erro de banco de dados ao tentar selecionar o empréstimo.');
            } else {
                //Carregando models necessários
                $this->load->model('DAOUsuario');
                
                $value = $result->row();
                $emprestimo = new TOEmprestimo();
                $emprestimo->id = $value->id;
                $emprestimo->data_saida = $value->data_saida;
                $emprestimo->data_retorno = $value->data_retorno;
                $emprestimo->data_finalizacao = $value->data_finalizacao;

                //Usuário que solicitou o empréstimo e admin que realizou o empréstimo
                $emprestimo->usuario = $this->DAOUsuario->get_user($value->usuario_id);
                $emprestimo->usuario_admin = $this->DAOUsuario->get_user($value->usuario_admin_id);

                //Seleciona os sub-emprestimos do emprestimo
                $emprestimo->emprestimo_item = $this->get_loans($emprestimo->id);
                return $emprestimo;
            }
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    /**
     * Retorna os empréstimos do usuário de acordo com seu id
     * 
     * @param  int      $usuario_id
     * @return array
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function get_loans_user($usuario_id) {
        try {
            $this->db->where('usuario_id', $usuario_id);
            $this->db->order_by('data_saida', 'DESC');
            $result = $this->db->get('emprestimo');

            if (!$result) {
                throw new Exception('Ocorreu um erro de banco de dados ao tentar selecionar os empréstimos do usuário.');
            } else {
                $emprestimos = array();
                foreach ($result->result() as $value) {
                    $emprestimo = new TOEmprestimo();
                    $emprestimo->id = $value->id;
                    $emprestimo->data_saida = $value->data_saida;
                    $emprestimo->data_retorno = $value->data_retorno;
                    $emprestimo->data_finalizacao = $value->data_finalizacao;
                   
                    //Seleciona os sub-emprestimos do emprestimo
                    $emprestimo->emprestimo_item = $this->get_loans($emprestimo->id);
                    
                    array_push($emprestimos, $emprestimo);
                }
                return $emprestimos;
            }
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    
    /**
     * Retorna os <b>sub-emprestimos</b> de acordo com o id do emprestimo
     * - Um emprestimo pode ter vários emprestimos (sub-emprestimos) de itens
     * 
     * @param type $id_emprestimo
     * @return array
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function get_loans($id_emprestimo) {
        try {
            $this->db->select('emprestimo_id, item_codigo, total, total_devolvido, status, item.item_tipo_id AS item_tipo');
            $this->db->join('item', 'item.codigo = item_codigo');
            $this->db->where('emprestimo_id', $id_emprestimo);
            $result = $this->db->get('emprestimo_has_item');

            if (!$result) {
                throw new Exception('Ocorreu um erro de banco de dados ao tentar selecionar empréstimos do item.');
            } else {
                //Carregando models necessários
                $this->load->model('DAOItem');
                $emprestimos = array();
                foreach ($result->result() as $value) {
                    $emprestimo_item = new TOEmprestimoItem();
                    $emprestimo_item->total = $value->total;
                    $emprestimo_item->total_devolvido = $value->total_devolvido;
                    $emprestimo_item->status = $value->status;
                    $emprestimo_item->item = new TOItem();
                    $emprestimo_item->item->codigo = $value->item_codigo;
                    $emprestimo_item->item->tipo = new TOTipo();
                    $emprestimo_item->item->tipo->id = $value->item_tipo;
                    //Selecionando o item
                    $emprestimo_item->item = $this->DAOItem->get_item($emprestimo_item->item);
                    array_push($emprestimos, $emprestimo_item);
                }
                return $emprestimos;
            }
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    
    /**
     * Retorna os emprestimos de um Item de acordo com seu código
     * 
     * @param type $item_codigo     Código do item,
     * @param type $init            Valor inicial do cursor no select
     * @param type $quant           Total de regitros máximo que deverá retornar
     * @return array                Array contendo os emprestimos de um item
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function get_loans_item($item_codigo, $init, $quant, $all = FALSE) {
        try {
            $this->db->join('emprestimo_has_item e_item', 'e_item.emprestimo_id = e.id');
            $this->db->where('e_item.item_codigo', $item_codigo);
            $this->db->order_by('e.data_saida', 'DESC');
            $result = $all == FALSE ? $this->db->get('emprestimo e', $quant, $init) : $this->db->get('emprestimo e');

            if (!$result) {
                throw new Exception('Ocorreu um erro de banco de dados ao tentar selecionar empréstimos do item.');
            } else {
                //Carregando models necessários
                $this->load->model('DAOUsuario');
                $emprestimos = array();
                foreach ($result->result() as $value) {
                    $emprestimo = new TOEmprestimo();
                    $emprestimo->id = $value->id;
                    $emprestimo->data_saida = $value->data_saida;
                    $emprestimo->data_retorno = $value->data_retorno;
                    
                    //Usuário que solicitou o empréstimo e admin que realizou o empréstimo
                    $emprestimo->usuario = $this->DAOUsuario->get_user($value->usuario_id);
                    $emprestimo->usuario_admin = $this->DAOUsuario->get_user($value->usuario_admin_id);
                    
                    $emprestimo->emprestimo_item = new TOEmprestimoItem();
                    $emprestimo->emprestimo_item->total = $value->total;
                    $emprestimo->emprestimo_item->total_devolvido = $value->total_devolvido;
                    $emprestimo->emprestimo_item->status = $value->status;
                    
                    array_push($emprestimos, $emprestimo);
                }
                return $emprestimos;
            }
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    /**
     * retorna o total de empréstimos
     * 
     * @param  bool $active     Empréstimos ativos
     * @return type
     */
    public function amount_all_loan($active = FALSE) {
        $this->db->select('id');
        $this->db->join('emprestimo_has_item', 'emprestimo_id = id');
        $this->db->group_by('emprestimo_id');
        $result = $this->db->get('emprestimo')->result();
        
        if ($active) {
            $emp_item = new TOEmprestimoItem();
            $emprestimos = array();
            foreach ($result as $value) {
                $emprestimo = new TOEmprestimo();
                $emprestimo->id = $value->id;
                $emprestimo->emprestimo_item = new TOEmprestimoItem();
                $emprestimo->emprestimo_item = $this->get_loans($emprestimo->id);

                $status = array();
                foreach ($emprestimo->emprestimo_item as $emprestimo_item) {
                    array_push($status, $emprestimo_item->status);
                }
                $status_name = $emp_item->get_status_loan($status, NULL, TRUE);

                /** Adiciona no array apenas os emprestimos ATIVOS com data de entrega vencida * */
                if ($status_name === TRUE) {
                    array_push($emprestimos, $emprestimo->id);
                }
            }
            return count($emprestimos);
        }  else {
            return count($result);
        }
        
    }

    /**
     * Retorna o total de empréstimos do item
     * 
     * @param type $item_codigo
     * @return type
     */
    public function amount_all_loan_item($item_codigo) {
        $this->db->where('item_codigo', $item_codigo);
        return $this->db->count_all_results('emprestimo_has_item');
    }
    
    
    /**
     * Verifica se o item estar apto para ser emprestado.
     * Caso não esteja é lançado uma excecao
     * 
     * @param  TOItem $item             Objeto contendo os dados do item
     * @param  int    $total_solicitar  Total do item a ser solicitado para o empéstimo
     * @return $messege                 Retorna mensagem casa não passar na validação e NULL se passar
     */
    public function check_availability_item(TOItem $item, $total_solicitar = NULL) {
        $this->load->helper('string_util');
        $this->load->model('DAOMovimentacao');
        $item->movimentacao = $this->DAOMovimentacao->get_movimentacao_item($item->codigo);

        if ($item->movimentacao->total_manipulacao == 0) {
            $messege = ('<p>A quantidade do item disponível para empéstimo: <span class="bold">' . $item->titulo . '</span> é igual a: <span class="bold">"0"</span>. Por isso não é possível realizar empréstimos do item.</p>');
        } else if ($item->movimentacao->total_manipulacao != 0 && $item->movimentacao->total_disponivel == 0) {
            $messege = ('<p>Não há quantidade disponível para este item: <span class="bold">' . $item->titulo . '.</span></p><p class="bold">Todos disponíveis estão com EMPRÉSTIMO ATIVO...</p>');
        } else if ($item->movimentacao->status == 0) {
            $messege = ('<p>O Status do item: <span class="bold">' . $item->titulo . '</span> estar marcado como <span class="bold">INATIVO.</span></p><p><span class="bold">Motivo da inatividade: </span>' . $item->movimentacao->motivo_inatividade . '</p>');
        } else if ($total_solicitar > $item->movimentacao->total_disponivel) {
            $messege = ('<p>A quantidade solicitada do item: <span class="bold">' . $item->titulo . '</span> excede o total de: <span class="bold">' . string_fill($item->movimentacao->total_disponivel, 2, 0, TRUE) . '</span> disponível para empréstimos.</p>');
        } else {
            // Passou nos possíveis casos de validação
            $messege = NULL;
        }

        return $messege;
    }
    
    /**
     * Verifica se o empréstimo está apto par aser realizado
     * - Algus parâmetros de configuração são checados:
     * - Total de itens por empréstimo.
     * - Total de empréstimo ATIVO por cada usuário...
     * 
     * @param TOEmprestimo $emprestimo
     * @throws ExceptionDAO
     */
    public function check_loan_apt(TOEmprestimo $emprestimo){
        try {
            $this->load->model('DAOConfig');
            $config = $this->DAOConfig->get_config();
            $loans_ativos = $this->amount_all_loan_user($emprestimo->usuario->id, FALSE, TRUE);
            $message = '<h3>Não foi possível realizar o empréstimo solicitado!</h3>';
            
            /**
             * Verifica o total de empréstimos ATIVOS que o usuário tem e verifica com o total permitido.
             */
            if(($config->limit_emprestimo == $loans_ativos) || ($loans_ativos > $config->limit_emprestimo)){
                throw new Exception('<p>O usuário: <span class="bold">' . $emprestimo->usuario->nome . '</span> possui o total de: <span class="bold">' . string_fill($loans_ativos, 2, 0) . '</span> empréstimos ATIVOS.</p>
                    <p>Apenas é permitido o tatal de: <span class="bold">' . string_fill($config->limit_emprestimo, 2, 0) . '</span> empréstimos ATIVOS para cada usuário.</p>');
            }
            /**
             * Verifica se o total de itens solicitados no empréstido excede o total permitido
             */
            else if($emprestimo->total_itens > $config->limit_item_emprestimo){
                throw new Exception('<p>O total de: <span class="bold">' . string_fill($emprestimo->total_itens, 2, 0) .  '</span> itens solicitados para o empréstimo, excede o total de: <span class="bold">' . string_fill($config->limit_item_emprestimo, 2, 0) . '</span> permitido.</p>');           
            }
            
        } catch (Exception $e) {
            throw new ExceptionValidacao($message . $e->getMessage());
        }
    }
    

    /**
     * Cadastra novos empréstimos
     * 
     * @param TOEmprestimo $emprestimo
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function insert_loan(TOEmprestimo $emprestimo){
        try {
            $this->db->trans_start();
            
            $this->db->set('data_saida', $emprestimo->data_saida);
            $this->db->set('data_retorno', $emprestimo->data_retorno);
            $this->db->set('usuario_id', $emprestimo->usuario->id);
            $this->db->set('usuario_admin_id', $emprestimo->usuario_admin->id);
            $result = $this->db->insert('emprestimo');
            
            if (!$result) {
                //Pegando numero do erro
                $erro = new MapError();
                throw new Exception($erro->getError($this->db->_error_number(), '<p>Ocorreu um erro de banco de dados ao tentar inserir empréstimo.</p>'));
            } else {
                $emprestimo->id = $this->db->insert_id(); // Pegando o id do emprestimo inserido
                
                //INSERIR emprestimos_item
                $this->insert_loan_item($emprestimo);
                 
                if ($this->db->trans_status() === FALSE) {
                    throw new Exception('Ocorreu um erro de banco de dados ao tentar inserir o empréstimo.');
                }
            }
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    
    /**
     * Cadastra os empréstimos do item
     * 
     * @param TOEmprestimo $emprestimo
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function insert_loan_item(TOEmprestimo $emprestimo) {
        try {
            $emprestimos_item = array();
            $this->load->model('DAOMovimentacao');
            foreach ($emprestimo->emprestimo_item as $key => $value) {
                $data['emprestimo_id'] = $emprestimo->id;
                $data['item_codigo'] = $value->item->codigo;
                $data['total'] = $value->total;
                $data['status'] = TOEmprestimoItem::EMPRESTIMO_ATIVO;
                array_push($emprestimos_item, $data);

                $emprestimo_item_vez = new TOEmprestimoItem();
                $emprestimo_item_vez->total = $data['total'];
                $emprestimo_item_vez->status = $data['status'];
                $emprestimo_item_vez->item = new TOItem();
                $emprestimo_item_vez->item->codigo = $value->item->codigo;
                $emprestimo_item_vez->item->titulo = $value->item->titulo;
                $this->set_movimentacao_loan_item($emprestimo_item_vez);
            }
            $result = $this->db->insert_batch('emprestimo_has_item', $emprestimos_item);
            
            if (!$result) {
                throw new Exception('Erro de banco de dados ao tentar inserir empréstimo do item.');
            }
            
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    /**
     * Atualiza a movimentacao do item de acordo com a solicitação de empréstimo
     * 
     * @param TOEmprestimoItem $emprestimo_item
     * @throws ExceptionDAO
     * @throws Exception
     */
    private function set_movimentacao_loan_item(TOEmprestimoItem $emprestimo_item) {
        try {
            $this->load->model('DAOMovimentacao');
            $emprestimo_item->item->movimentacao = $this->DAOMovimentacao->get_movimentacao_item($emprestimo_item->item->codigo);

            /** Estar solicitando o empréstimo, pegando o item * */
            if (($emprestimo_item->item->movimentacao->total_disponivel >= $emprestimo_item->total) && ($emprestimo_item->status == 1)) {
                $emprestimo_item->item->movimentacao->total_disponivel -= $emprestimo_item->total;

                $this->DAOMovimentacao->mark_movimentacao_loan($emprestimo_item->item);
            } else {
                throw new Exception("O item: <span class='bold'>" . $emprestimo_item->item->titulo . "</span>. Não está apto para empréstimos.");
            }

            $this->db->trans_complete();
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    
    /**
     * Atualiza a movimentacao do item de acordo com a solicitação de empréstimo
     * 
     * @param TOEmprestimoItem $emprestimo_item
     * @throws ExceptionDAO
     * @throws Exception
     */
    private function up_movimentacao_loan_item(TOEmprestimoItem $emprestimo_item, $codigo_emprestimo) {
        try {
            $this->db->set('total_devolvido', $emprestimo_item->total_devolvido);
            $this->db->set('status', $emprestimo_item->status);
            $this->db->where('emprestimo_id', $codigo_emprestimo);
            $this->db->where('item_codigo', $emprestimo_item->item->codigo);

            $result = $this->db->update('emprestimo_has_item');

            if (!$result) {
                throw new Exception('Ocorreu um erro de banco de dados ao tentar atualizar dados do item de acordo com o empréstimo.');
            }

            $this->db->trans_complete();
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }

    /**
     * Efetua busca por empréstimos
     * Podendo a busca ser pelo codigo do item, título, nome do usuário, data de sáida ou data de retorno.
     * O OR_LIKE é utilizado para efetuar a busca.
     * 
     * @param type $init
     * @param type $quant
     * @param type $term
     * @return array
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function search_loan($init, $quant, $term = NULL, $orderby = NULL, $direction = NULL) {
        try {
            $this->load->helper('string_util');
            // Se conter os caracteres / ou - o termo da busca é tratado como data
            if ((strstr($term, "/")) || (strstr($term, "-"))) {
                $term = format_date($term);
            }

            $orderby != NULL && $direction != NULL ? $this->db->order_by($orderby, $direction) : $this->db->order_by('e.data_saida', 'DESC');
            $this->db->select('e.id, e.data_saida, e.data_retorno, e.usuario_id, e.usuario_admin_id, usuario.nome AS usuario');
            $this->db->join('emprestimo_has_item e_item', 'e_item.emprestimo_id = e.id');
            $this->db->join('item', 'item.codigo = e_item.item_codigo');
            $this->db->join('usuario', 'usuario.id = e.usuario_id');
            $this->db->like('e.id', $term);
            $this->db->or_like('item.titulo', $term);
            $this->db->or_like('usuario.nome', $term);
            $this->db->or_like('e.data_saida', $term);
            $this->db->or_like('e.data_retorno', $term);
            $this->db->group_by('e_item.emprestimo_id');
            $result = $this->db->get('emprestimo e', $quant, $init);
            
            //Caso ocorra erro no select
            if (!$result) {
                throw new Exception('Ocorreu um erro de banco de dados ao tentar buscar empréstimos.');
            } else {
                //Carregando models necessários
                $this->load->model('DAOUsuario');               
                $emprestimos = array();
                foreach ($result->result() as $value) {
                    $emprestimo = new TOEmprestimo();
                    $emprestimo->id = $value->id;
                    $emprestimo->data_saida = $value->data_saida;
                    $emprestimo->data_retorno = $value->data_retorno;
                    $emprestimo->emprestimo_item = new TOEmprestimoItem();
                    $emprestimo->emprestimo_item = $this->get_loans($emprestimo->id);

                    //Usuário que solicitou o empréstimo e admin que realizou o empréstimo
                    $emprestimo->usuario = $this->DAOUsuario->get_user($value->usuario_id);
                    $emprestimo->usuario_admin = $this->DAOUsuario->get_user($value->usuario_admin_id);

                    array_push($emprestimos, $emprestimo);
                }
                return $emprestimos;
            }
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }

    /**
     * Retorna a quantidade de registros da busca por emprestimos
     * 
     * @param string $term
     * @return int
     */
    public function amount_search_loan($term) {
        $this->load->helper('string_util');
        // Se conter os caracteres / ou - o termo da busca é tratado como data
        if ((strstr($term, "/")) || (strstr($term, "-"))) {
            $term = format_date($term);
        }
        $this->db->select('e.id, e.data_saida, e.data_retorno, e.usuario_id, e.usuario_admin_id');
        $this->db->join('emprestimo_has_item e_item', 'e_item.emprestimo_id = e.id');
        $this->db->join('item', 'item.codigo = e_item.item_codigo');
        $this->db->join('usuario', 'usuario.id = e.usuario_id');
        $this->db->like('e.id', $term);
        $this->db->or_like('item.titulo', $term);
        $this->db->or_like('usuario.nome', $term);
        $this->db->or_like('e.data_saida', $term);
        $this->db->or_like('e.data_retorno', $term);
        $this->db->group_by('e_item.emprestimo_id');
        $result = $this->db->get('emprestimo e');

        return count($result->result());
    }
    
    
    /**
     * Verifica se existe empréstimo cadastrado de acordo com o codigo passado como parametro
     * - TRUE é retornado caso possua cadastro
     * - FALSE é retornado caso não possua acadastro
     * 
     * @param  int $codigo_emprestimo
     * @return boolean
     */
    public function check_loan($codigo_emprestimo) {
        $this->db->where('id', $codigo_emprestimo);

        if ($this->db->count_all_results('emprestimo') > 0)
            return TRUE;
        else
            return FALSE;
    }
    
    
    /**
     * Retorna o total de empréstimos do usuário
     * - Para usuários Administrador é retornado o total que ele cadastrou
     * - Para usuários Comum é retornado o total de empréstimos solicitados
     * 
     * @param  int  $usuario_id     Código do usuário
     * @param  bool $admin          Se o usuário é Administrador ou usuário Comum. FALSE é o default
     * @param  bool $active         Filtrar por empretimos ATIVOS ou TODOS. FALSE é o default
     *  - Por default é FALSE
     * @return int
     */
    public function amount_all_loan_user($usuario_id, $admin = FALSE, $active = FALSE) {
        //Caso seja solicitado contar o tatal de empréstimo que não ativos
        if ($admin) { // Se for admin
            $this->db->where('usuario_admin_id', $usuario_id);
        } else { // Se for usuário comum
            $this->db->where('usuario_id', $usuario_id);
        }
              
        if (!$active) {
            $this->db->select('id');
        } else {
            $this->db->select('id, GROUP_CONCAT(e_item.status) AS status');
            $this->db->join('emprestimo_has_item e_item', 'e_item.emprestimo_id = id');
            $this->db->group_by('id');
        }

        $result = $this->db->get('emprestimo');
        
        $total = 0;
        if ($active) {
           $emprestimo_item = new TOEmprestimoItem();
           foreach ($result->result() as $value){
               $status = explode(",", $value->status);
               $emprestimo_item->get_status_loan($status, 1, TRUE) ? $total++ : '';
           }
        }else {
            $total = count($result->result());
        }

        return $total;
    }
    
    /**
     * Atualiza o empréstimo, levando em considerações as possíveis exceções
     * 
     * @param TOEmprestimo $emprestimo
     * @throws ExceptionDAO
     * @throws ExceptionValidacao
     * @throws Exception
     */
    public function update_loan_item(TOEmprestimo $emprestimo) {
        try {
            $emprestimo_item_original = $this->get_loans($emprestimo->id);
            
            /**
             * Verifica o status do empréstimo
             * - Se FINALIZADO é salvo a data e hora da finalização
             * - Se estiver ATIVO salva a data de finalização como NULL
             */
            $this->check_status_loan($emprestimo, NULL, TRUE) == TRUE ? $this->db->set('data_finalizacao', NULL) : $this->db->set('data_finalizacao', date('Y-m-d H:i:s'));
            $this->db->where('id', $emprestimo->id);
            $this->db->update('emprestimo');
            
            /**
             * Atualiza os dados dos sub-emprestimos e movimentacao de cada item
             */
            foreach ($emprestimo->emprestimo_item as $index => $emprestimo_item) {
                $total_devolver = 0;

                $item = new TOItem();
                $item->codigo = $emprestimo_item->item->codigo;
                $item->movimentacao = new TOMovimentacao();

                /** Devolvendo Itens * */
                if (($emprestimo_item->item->codigo == $emprestimo_item_original[$index]->item->codigo) && ($emprestimo_item->total_devolvido > $emprestimo_item_original[$index]->total_devolvido)) {
                    $total_devolver = $emprestimo_item->total_devolvido;
                    /**
                     *  Total disponivel do banco + (Total a devolver + Total já devolvido)
                     */
                    $total_disponivel = $emprestimo_item_original[$index]->item->movimentacao->total_disponivel + ($total_devolver - $emprestimo_item_original[$index]->total_devolvido);
                    $item->movimentacao->total_disponivel = $total_disponivel;

                    /** Pegando de volta itens antes marcados como devolvidos | Rebrindo empréstimo **/
                } else if (($emprestimo_item->item->codigo == $emprestimo_item_original[$index]->item->codigo) && ($emprestimo_item->total_devolvido < $emprestimo_item_original[$index]->total_devolvido)) {
                    /**
                     * Verifica se é possível retirar o item novamente
                     * Só é possível se ainda os itens antes devolvido ainda estiverem disponíveis
                     */
                    if (abs(($emprestimo_item->total_devolvido - $emprestimo_item_original[$index]->total_devolvido)) > $emprestimo_item_original[$index]->item->movimentacao->total_disponivel) {
                        throw new ExceptionValidacao('<p>Não é possível retirar novamente o total do item: <span class="bold">' . $emprestimo_item_original[$index]->item->titulo . '</span></p><p><span class="bold">A quantidade devolvida já possui EMPRÉSTIMOS ATIVOS...</p></span>');
                    } else {
                        $total_devolver = $emprestimo_item->total_devolvido;
                        /**
                         *  Total disponivel do banco - (Total a devolver - Total já devolvido)
                         *  Como é uma subtração a função abs é usada par aretornar sempre numeros positivos
                         */
                        $total_disponivel = abs($emprestimo_item_original[$index]->item->movimentacao->total_disponivel - abs(($total_devolver - $emprestimo_item_original[$index]->total_devolvido)));
                        $item->movimentacao->total_disponivel = $total_disponivel;
                    }
                } else {
                    // Se o dado da vez não entrar em nehuma condição, o Laço é interrompido aqui e pulado para o próximo da lista
                    continue;
                }
                $this->db->trans_start();

                // Atualiza os dados do emprestimo_item da vez
                $this->db->set('total_devolvido', $emprestimo_item->total_devolvido);
                $this->db->set('status', $emprestimo_item->status);
                $this->db->where('emprestimo_id', $emprestimo->id);
                $this->db->where('item_codigo', $emprestimo_item->item->codigo);
                $this->db->update('emprestimo_has_item');

                // Atualiza a movimentacao do item da vez
                $this->DAOMovimentacao->mark_movimentacao_loan($item);

                $this->db->trans_complete();
            }
            
            if ($this->db->trans_status() === FALSE) {
                throw new Exception('Ocorreu um erro de banco de dados ao tentar atualizar dados do empréstimo');
            }
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
    
    /**
     * Remove empréstimo
     * 
     * @param  $codigo_emprestimo
     * @throws ExceptionDAO
     * @throws Exception
     */
    public function delete_loan($codigo_emprestimo) {
        try {
            $this->db->trans_start();
            
            $ids_emprestimo = explode(',', $codigo_emprestimo);
            
            foreach ($ids_emprestimo as $emprestimo_vez) {
                $emprestimo = $this->get_loans($emprestimo_vez);
                $this->db->where('id', $emprestimo_vez);
                $this->db->delete('emprestimo');
                
                foreach ($emprestimo as $emprestimo_item) {
                    $item = new TOItem();
                    $item->movimentacao = new TOMovimentacao();
                    $item->codigo = $emprestimo_item->item->codigo;
                    /**
                     * Total disponivel do banco + Total que ainda não foi entregue
                     */
                    $item->movimentacao->total_disponivel = $emprestimo_item->item->movimentacao->total_disponivel + ($emprestimo_item->total - $emprestimo_item->total_devolvido);
                    $item->movimentacao->total_emprestado = $emprestimo_item->item->movimentacao->total_disponivel - 1;
                   
                    /**
                     * Se for maior que zero. OU seja, se ainda não faltou item para ser entregue
                     * - Atualiza a movimentacao do item da vez
                     */
                    $item->movimentacao->total_disponivel > 0 ? $this->DAOMovimentacao->mark_movimentacao_loan($item) : '';
                }
            }
            
            if ($this->db->trans_status() === FALSE) {
                throw new Exception('Ocorreu um erro de banco de dados ao tentar remover o empréstimo de código: <span class="bold">' . $codigo_emprestimo . '</span>');
            }
        } catch (Exception $e) {
            throw new ExceptionDAO($e->getMessage());
        }
    }
    
        
    /**
     * Retorna o status GERAL do empréstimo. Levando em consideração o status de cada sub-empréstimo
     * 
     * @param TOEmprestimo $emprestimo  Obejto empréstimo contendo os dados
     * @param int   $option             Determina o tipo da string Ativo/Inativo e Disponível/Indisponível
     * @param bool  $bool               Se TRUE retornará o valor booleano e não String. FALSE é o valor default
     * @return type
     */
    public function check_status_loan(TOEmprestimo $emprestimo, $option, $bool = FALSE) {
        //Monta um array com os status dos sub-emprestimos dos itens
        $status_item = array();
        foreach ($emprestimo->emprestimo_item as $emprestimo_item) {
            array_push($status_item, $emprestimo_item->status);
        }
        //Pegando o status geral do empréstimo de acordo com os status dos sub-emprestimos
        $emprestimo_item = new TOEmprestimoItem();
        return $emprestimo_item->get_status_loan($status_item, $option, $bool);
    }

}